﻿module Program
open System
open System.Collections.Generic
open System.IO
open MathNet.Numerics
open MathNet.Numerics.FSharp
open MathNet.Numerics.LinearAlgebra.Double
open BernulliMixture
open System.Drawing
open System.Windows.Forms
open Types
open Utils

//lettura dei dati da file
let stream = File.Open("..\..\data\semeion.data",FileMode.Open, FileAccess.Read)
let stream_reader = new StreamReader(stream) 
let text = stream_reader.ReadToEnd()
stream_reader.Close()
stream.Close()


let labels = Map.ofList([("Iris-setosa",0.); ("Iris-versicolor",1.); ("Iris-virginica",2.)])
let k = 15

let input =

    let splitted_text = text.Split('\n')  
                        |> Seq.filter(fun elem -> elem <> "") 
                        |> Seq.toList

    let rec build_vectors (list : (int*string) list) =
      match list with
      []  -> []
      |(i,x)::xs -> 
        let first_266 = x.Split(' ', '\r')  
                            |> Seq.filter(fun elem -> elem <> "") 
                            |> Seq.map(fun p -> float p) 
                            
        let first_256 = first_266 |> Seq.take 256 |> Seq.toArray
        let real_number   = first_266 |> Seq.skip 256 |> Seq.mapi(fun i p -> if float p = 1.0 then i else 0) |> Seq.sum


        let points = new DenseVector(first_256)

        DenseVectorWrapper(points, i, real_number, -1 |> ref, DenseVector(k)) :: build_vectors xs
        
    

    build_vectors (splitted_text |> List.mapi(fun i s -> (i,s)))

//test function
let compute_bernullimixture (k : int) (input : DenseVectorWrapper list) =
  
  let init_mu = [for k in [0..k-1] do 
                  let vector = [for cmp in [0..input.Head.DenseVector.Count-1] do yield seed.NextDouble() * 0.5 + 0.25] |> List.toArray 
                  yield DenseVectorWrapper(DenseVector(vector) , k, k, ref k, DenseVector(1))]
  let init_pi = [for _ in [0..k-1] do yield 1. / float k]
  do compute_probabilities input init_mu

  let gammas = DenseMatrix(input.Length, k)
  let continue_loop = ref true
  
  let rec compute_mu (mu_list : DenseVectorWrapper list) pi_list   =
    continue_loop := true
    let prev_mu_list = mu_list
    
    
    //compute gamma
    do compute_probabilities input mu_list
    for p in input do
      for k in [0..k-1] do
        
        gammas.[p.Index,k] <- gamma_znk pi_list mu_list k p
    


    //compute mu
    let next_mu = [for mu in mu_list do 
                    let res = u_k gammas mu_list mu.Index input
                    if !continue_loop then                    
                      for k = 0 to mu.DenseVector.Count - 1 do 
                        if Math.Abs(mu.DenseVector.[k] - res.DenseVector.[k]) > 0.001 then
                          continue_loop := false
                    yield res]
    
    //disegno
    do graphics.Clear(white_color)

    let next_mu_wrapper = next_mu 
                            |> List.mapi(fun i mu -> (i,mu))
                            |> List.map(fun (i,mu) -> DenseVectorWrapper(mu.DenseVector,i,-1,ref i, DenseVector(1)))

    let prev_mu_wrapper = prev_mu_list
                            |> List.mapi(fun i mu -> (i,mu))
                            |> List.map(fun (i,mu) -> DenseVectorWrapper(mu.DenseVector,i,-1,ref i, DenseVector(1)))

    for mu, prev_mu in List.zip next_mu_wrapper prev_mu_wrapper do
      let prev_mu_k_matrix = prev_mu.toMatrix16x16
      let mu_k_matrix = mu.toMatrix16x16
      do draw_point mu_k_matrix prev_mu_k_matrix mu.Index

    f.Update()

    //compute pi 
    let next_pi = [for mu in next_mu do yield pi_k gammas mu.Index input.Length input]


    do compute_r input

    if not !continue_loop then      
      compute_mu next_mu next_pi
    else mu_list
  compute_mu init_mu init_pi

let res = compute_bernullimixture k input
System.Console.Write(res)
System.Threading.Thread.Sleep(10000)
()